package org.wu.framework.lazy.orm.database.sql.expand.database.persistence.method.ddl;

import lombok.extern.slf4j.Slf4j;
import org.wu.framework.core.NormalUsedString;
import org.wu.framework.core.stereotype.LayerField;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.lazy.orm.core.config.enums.DDLAuto;
import org.wu.framework.lazy.orm.core.persistence.conf.*;
import org.wu.framework.lazy.orm.core.persistence.conf.index.AbstractLazyTableIndexEndpoint;
import org.wu.framework.lazy.orm.core.persistence.conf.mysql.ClassLazyTableEndpoint;
import org.wu.framework.lazy.orm.core.persistence.map.EasyHashMap;
import org.wu.framework.lazy.orm.core.source.SqlSourceClass;
import org.wu.framework.lazy.orm.core.source.adapter.SourceFactory;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.method.AbstractLazyOperationMethod;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.method.LazyOperationParameter;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * description ddl抽象方法
 *
 * @author Jia wei Wu
 * @date 2023/01/15 21:48
 */
@Slf4j
public abstract class AbstractLazyDDLOperationMethod extends AbstractLazyOperationMethod implements LazyDDLOperationMethod {
    public AbstractLazyDDLOperationMethod(LazyOperationParameter lazyOperationParameter) {
        super(lazyOperationParameter);
    }

    /**
     * describe 完善表
     *
     * @param connection  连接对象
     * @param easyHashMap 实体对象
     * @return boolean 执行成功或者失败
     * @author Jia wei Wu
     * @date 2022/1/2 5:41 下午
     **/
    public synchronized boolean perfect(Connection connection, EasyHashMap easyHashMap) throws SQLException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        final ClassLazyTableEndpoint lazyTableEndpoint = easyHashMap.toEasyTableAnnotation(false, true);
        return perfect(connection, lazyTableEndpoint);
    }


    /**
     * describe 完善表
     *
     * @param connection  连接对象
     * @param entityClass 实体对象class
     * @return boolean 执行成功或者失败
     * @author Jia wei Wu
     * @date 2022/1/2 5:41 下午
     **/
    public synchronized boolean perfect(Connection connection, Class entityClass, DDLAuto ddlAuto) throws SQLException, NoSuchFieldException, InstantiationException, IllegalAccessException {

        // 本地缓存实体class
        if (LazyDatabaseJsonMessage.localCacheEntityClass.contains(entityClass)) {
            return true;
        }
        if (!EasyHashMap.class.isAssignableFrom(entityClass)) {
            LazyDatabaseJsonMessage.localCacheEntityClass.add(entityClass);
        }
//        LazyTableEndpoint lazyTableEndpoint = LazyTableUtil.analyzeLazyTable(entityClass);
        SqlSourceClass sqlSourceClass = SqlSourceClass.getInstance(entityClass);
        LazyTableEndpoint<?> lazyTableEndpoint = sqlSourceClass.getLazyTableEndpoint();
        return perfect(connection, lazyTableEndpoint, ddlAuto);
    }


    /**
     * describe 完善表
     *
     * @param connection        连接对象
     * @param lazyTableEndpoint 实体对象 schema
     * @return
     * @author Jia wei Wu
     * @date 2022/1/2 5:41 下午
     **/
    public synchronized boolean perfect(Connection connection, LazyTableEndpoint lazyTableEndpoint) throws SQLException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        return perfect(connection, lazyTableEndpoint, DDLAuto.PERFECT);
    }

    /**
     * describe 完善表
     *
     * @param connection        连接对象
     * @param lazyTableEndpoint 实体对象 schema
     * @param ddlAuto           ddl 类型
     * @return boolean 执行成功或者失败
     * @author Jia wei Wu
     * @date 2022/1/2 5:41 下午
     **/
    public synchronized boolean perfect(Connection connection, LazyTableEndpoint lazyTableEndpoint, DDLAuto ddlAuto) throws SQLException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        boolean exist = lazyTableEndpoint.isExist();
        if (exist) {
            Statement statement = connection.createStatement();
            // 查询表是否存在
            List<LazyTableInfo> lazyTableInfos = findTableInfo(connection, lazyTableEndpoint);
            if (ObjectUtils.isEmpty(lazyTableInfos)) {
                // 创建表
                String createTableSQL = lazyTableEndpoint.creatTableSQL();
                for (String sql : createTableSQL.split(NormalUsedString.SEMICOLON)) {
                    statement.execute(sql);
                }

                log.warn("create table {} success", lazyTableEndpoint.getTableName());
            } else {
                // 表存在  不需要创建
            }
            if (DDLAuto.CREATE.equals(ddlAuto)) {
                // 默认都会被执行的
            } else {
                // 更新表数据
                // 查询表原始字段
                List<LazyColumn> lazyColumnCollection = findTableColumnList(connection, lazyTableEndpoint);
                // 查询表索引
                List<LazyColumnIndex> lazyColumnIndexList = findTableColumnIndexList(connection, lazyTableEndpoint);

                // 字段索引降维度
                Map<String, List<LazyColumnIndex>> columnIndexMap = lazyColumnIndexList.stream().collect(Collectors.groupingBy(LazyColumnIndex::getColumnName));

                List<LazyTableFieldEndpoint> currentColumnNameList = new ArrayList<>();
                for (LazyColumn lazyColumn : lazyColumnCollection) {
                    LazyTableFieldEndpoint oldFieldLazyTableFieldEndpoint = SourceFactory.getDefaultLazyTableFieldEndpointInstance();
                    oldFieldLazyTableFieldEndpoint.setColumnName(lazyColumn.getColumnName());
//                oldFieldLazyTableFieldEndpoint.setOrdinalPosition(lazyColumn.getOrdinalPosition());
                    oldFieldLazyTableFieldEndpoint.setDefaultValue(lazyColumn.getColumnDefault());
                    oldFieldLazyTableFieldEndpoint.setNotNull(!NormalUsedString.YES.equalsIgnoreCase(lazyColumn.getIsNullable()));
                    oldFieldLazyTableFieldEndpoint.setDataType(lazyColumn.getDataType());
//                oldFieldLazyTableFieldEndpoint.setCharacterMaximumLength(lazyColumn.getCharacterMaximumLength());
                    oldFieldLazyTableFieldEndpoint.setScale(lazyColumn.getNumericScale());
                    oldFieldLazyTableFieldEndpoint.setColumnType(lazyColumn.getColumnType());


                    oldFieldLazyTableFieldEndpoint.setExtra(lazyColumn.getExtra());
                    // 权限
//                oldFieldLazyTableFieldEndpoint.setPrivileges(lazyColumn.getPrivileges());
                    oldFieldLazyTableFieldEndpoint.setComment(lazyColumn.getColumnComment());
                    // 存在索引
                    if (columnIndexMap.containsKey(lazyColumn.getColumnName())) {
                        List<LazyColumnIndex> lazyColumnIndexs = columnIndexMap.get(lazyColumn.getColumnName());

                        LazyTableIndexEndpoint[] indexEndpoints = lazyColumnIndexs.stream().map(lazyColumnIndex -> {
                            AbstractLazyTableIndexEndpoint instance = AbstractLazyTableIndexEndpoint.getInstance();
                            // 索引名称
                            instance.setIndexName(lazyColumnIndex.getIndexName());
                            // 索引类型
                            instance.setFieldIndexType(lazyColumnIndex.isNonUnique() ? LayerField.LayerFieldType.NORMAL : LayerField.LayerFieldType.UNIQUE);
                            return instance;
                        }).collect(Collectors.toList()).toArray(new LazyTableIndexEndpoint[0]);
                        oldFieldLazyTableFieldEndpoint.setLazyTableIndexEndpoints(indexEndpoints);
                        // PRI 主键
                        oldFieldLazyTableFieldEndpoint.setKey(lazyColumnIndexs.stream().anyMatch(lazyColumnIndex -> NormalUsedString.PRIMARY.equals(lazyColumnIndex.getIndexName())));
                    }
                    currentColumnNameList.add(oldFieldLazyTableFieldEndpoint);
                }
                String alterTableSQL = null;
                boolean dropColumn = DDLAuto.PERFECT.equals(ddlAuto);
                alterTableSQL = lazyTableEndpoint.alterTableSQL(currentColumnNameList, dropColumn);
                if (!ObjectUtils.isEmpty(alterTableSQL)) {
                    log.debug("alter table sql:{}", alterTableSQL);
                    try {
                        boolean execute = statement.execute(alterTableSQL);
                    } catch (SQLException e) {
                        List<String> alterTableColumnSQL = lazyTableEndpoint.alterTableColumnSQL(currentColumnNameList, dropColumn);
                        for (String alertTableColumn : alterTableColumnSQL) {
                            try {
                                statement.execute(alertTableColumn);
                            } catch (Exception exception) {
                                log.warn("执行 单个字段更新 sql: " + alertTableColumn + "\n失败: " + exception);
                            }
                        }
                        throw new SQLException("执行sql 失败: " + alterTableSQL, e);
                    }
                } else {
                    log.info("表结构未发生变化");
                }

            }
            statement.close();
            return true;
        } else {
            log.warn("Ignore creating tables:" + lazyTableEndpoint.getTableName());
            return false;
        }
    }

    /**
     * 获取数据库schema
     *
     * @return 数据库schema
     */
    @Override
    public List<String> findSchemaList(Connection connection) {
        Statement statement = null;
        try {
            statement = connection.createStatement();
            // 获取sql
            String schemaListSql = SourceFactory.findSchemaListSql();

            // 执行sql
            ResultSet resultSet = statement.executeQuery(schemaListSql);
            List<String> schemaList = resultSetConverter(resultSet, String.class);
            // 返回结果
            return schemaList;

        } catch (SQLException | NoSuchFieldException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }

    /**
     * 查询原始表字段
     *
     * @param connection        数据库连接
     * @param lazyTableEndpoint java 模型
     * @return 表字段
     */
    @Override
    public List<LazyColumn> findTableColumnList(Connection connection, LazyTableEndpoint lazyTableEndpoint) {
        Statement statement = null;
        try {
            String schema = ObjectUtils.isEmpty(lazyTableEndpoint.getSchema()) ? (ObjectUtils.isEmpty(connection.getCatalog()) ? connection.getSchema() : connection.getCatalog()) : lazyTableEndpoint.getSchema();

            String table = SourceFactory.cleanSpecialColumn(lazyTableEndpoint.getTableName());
            statement = connection.createStatement();
            // 获取sql
            String findTableColumnListSql = SourceFactory.findTableColumnListSql(schema, table);

            // 执行sql
            ResultSet resultSet = statement.executeQuery(findTableColumnListSql);
            Class<? extends LazyColumn> columnInfoClass = SourceFactory.findColumnInfoClass();
            List<LazyColumn> lazyColumnList = resultSetConverter(resultSet, columnInfoClass);
            // 返回结果
            return lazyColumnList;

        } catch (SQLException | NoSuchFieldException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 查询索引
     *
     * @param connection        数据库连接
     * @param lazyTableEndpoint java 模型
     * @return 表索引
     */
    @Override
    public List<LazyColumnIndex> findTableColumnIndexList(Connection connection, LazyTableEndpoint lazyTableEndpoint) {
        Statement statement = null;
        try {
            String schema = ObjectUtils.isEmpty(lazyTableEndpoint.getSchema()) ? (ObjectUtils.isEmpty(connection.getCatalog()) ? connection.getSchema() : connection.getCatalog()) : lazyTableEndpoint.getSchema();

            String table = SourceFactory.cleanSpecialColumn(lazyTableEndpoint.getTableName());
            statement = connection.createStatement();
            // 获取sql
            String findTableColumnIndexListSql = SourceFactory.findTableColumnIndexListSql(schema, table);
            if(ObjectUtils.isEmpty(findTableColumnIndexListSql)){
                return List.of();
            }

            // 执行sql
            ResultSet resultSet = statement.executeQuery(findTableColumnIndexListSql);
            Class<? extends LazyColumnIndex> columnIndexInfoClass = SourceFactory.findColumnIndexInfoClass();
            List<LazyColumnIndex> lazyColumnIndexList = resultSetConverter(resultSet, columnIndexInfoClass);
            // 返回结果
            return lazyColumnIndexList;

        } catch (SQLException | NoSuchFieldException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 查询表信息
     *
     * @param connection        数据库连接
     * @param lazyTableEndpoint java 模型
     * @return 表信息
     */
    @Override
    public List<LazyTableInfo> findTableInfo(Connection connection, LazyTableEndpoint lazyTableEndpoint) {
        Statement statement = null;
        try {
            String schema = ObjectUtils.isEmpty(lazyTableEndpoint.getSchema()) ? (ObjectUtils.isEmpty(connection.getCatalog()) ? connection.getSchema() : connection.getCatalog()) : lazyTableEndpoint.getSchema();

            String table = SourceFactory.cleanSpecialColumn(lazyTableEndpoint.getTableName());
            statement = connection.createStatement();
            // 获取sql
            String findTableInfoSql = SourceFactory.findTableInfoSql(schema, table);

            // 执行sql
            ResultSet resultSet = statement.executeQuery(findTableInfoSql);
            Class<? extends LazyTableInfo> tableInfoClass = SourceFactory.findTableInfoClass();
            List<LazyTableInfo> lazyTableInfoList = resultSetConverter(resultSet, tableInfoClass);
            // 返回结果
            return lazyTableInfoList;

        } catch (SQLException | NoSuchFieldException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 更新表
     *
     * @param lazyTableEndpoint java 模型
     */
    @Override
    public void alertTable(LazyTableEndpoint lazyTableEndpoint) {

    }
}
